﻿// Copyright (c) 2012, Alexander Endris
// All rights reserved.
// 
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// * Redistributions of source code must retain the above copyright
//    notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in the
//    documentation and/or other materials provided with the distribution.
// 
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#region Usings

using System.Collections.Generic;
using System.IO;

#endregion

namespace Lyricsgrabber.Core.Tags.ID3
{
  internal class ID3Tag : Tag
  {
    #region Public / Attributes

    public static readonly string Tag = "ID3";

    public bool Exprimental
    {
      get { return exprimental; }
    }

    public bool ExtendedHeader
    {
      get { return extendedHeader; }
    }

    public byte Major
    {
      get { return major; }
    }

    public byte Minor
    {
      get { return minor; }
    }

    public int Size
    {
      get { return size; }
    }

    public bool Unsynchronisation
    {
      get { return unsynchronisation; }
    }

    #endregion

    #region Public / Methods

    public override void Save()
    {
    }

    #endregion

    #region Private / Attributes

    private bool exprimental;
    private bool extendedHeader;
    private byte major;
    private byte minor;
    private int size;
    private bool unsynchronisation;

    #endregion

    #region Private / Constructors

    internal ID3Tag(string fileName)
    {
      metadata = new List<IMetadata>();

      using (Stream str = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
      using (BinaryReader reader = new BinaryReader(str))
      {
        string tag = new string(reader.ReadChars(3));

        if (tag != Tag)
          throw new InvalidDataException("The specified file does not contain an ID3 tag!");

        major = reader.ReadByte();
        minor = reader.ReadByte();

        byte flags = reader.ReadByte();

        unsynchronisation = (flags & 0x80) != 0;
        extendedHeader = (flags & (0x80 >> 1)) != 0;
        exprimental = (flags & (0x80 >> 2)) != 0;

        size = (reader.ReadByte() & 0x7f) << 21;
        size |= (reader.ReadByte() & 0x7f) << 14;
        size |= (reader.ReadByte() & 0x7f) << 7;
        size |= (reader.ReadByte() & 0x7f);

        int start = (int) reader.BaseStream.Position;
        do
        {
          string frameId = new string(reader.ReadChars(4));
          if (frameId[0] == 0)
            break;

          int frameSize = reader.ReadByte() << 24;
          frameSize |= reader.ReadByte() << 16;
          frameSize |= reader.ReadByte() << 8;
          frameSize |= reader.ReadByte();
          short flag = reader.ReadInt16();

          ID3Frame frame = ID3FrameFactory.Create(reader, frameId, frameSize, flag);

          if (frame != null)
            metadata.Add(frame);
        } while (start + size > reader.BaseStream.Position);
      }
    }

    #endregion
  }
}